#include "XNode.h"

XNode::XNode(){
	m_parent = NULL;
	m_visible = true;
	m_update = true;
	m_scale = 1.0f;
}
XNode::~XNode(){
	RemoveAllChild();
}
void XNode::SetVisible(bool visible){
	m_visible = visible;
}
void XNode::AddChild(XNode* child){
	if (child->GetParent() != NULL){
		child->Retain();
		child->GetParent()->RemoveChild(child);
	}
	m_children.insert(m_children.end(), child);
	child->SetParent(this);
}
void XNode::RemoveChild(XNode* child){
	int i_index = 0;
	i_index = GetChildIndex(child);
	if (i_index == -1)
		return;
	m_children[i_index]->SetParent(NULL);
	m_children[i_index]->Release();
	m_children.erase(m_children.begin() + i_index);
}
void XNode::RemoveAllChild(){
	for each (XNode* ptr_node in m_children)
	{
		ptr_node->SetParent(NULL);
		ptr_node->Release();
	}
	m_children.clear();
}
XNode* XNode::GetChild(int index){
	return m_children[index];
}
int XNode::GetChildIndex(XNode* child){
	int i_iterator = 0, i_count = 0;
	i_count = m_children.size();
	for (i_iterator = 0; i_iterator < i_count; i_iterator++){
		if (child == m_children[i_iterator])
			return i_iterator;
	}
	return -1;
}
XNode* XNode::GetParent(){
	return m_parent;
}
void XNode::SetParent(XNode* parent){
	m_parent = parent;
}
Matrix4 XNode::GetTransform(){
	return m_finalMatrix;
}
Vector3 XNode::GetPosition(){
	return Vector3(m_finalMatrix.GetRow(3));
}
void XNode::SetScale(float scale){
	m_scale = scale;
	m_update = true;
}
float XNode::GetScale(){
	return m_scale;
}
bool XNode::IsVisible(){
	return m_visible;
}
void XNode::SetOffestToParent(Vector3 pos){
	Matrix3 offest = Matrix3::IDENTITY;
	if (m_parent != NULL)
		m_parent->GetTransform().Extract3x3Matrix(offest);
	offest = offest.Transpose();
	m_posParent = pos*offest;
	m_update = true;
}
Vector3 XNode::GetOffestToParent(){
	return m_posParent;
}
void XNode::SetRotationToParent(Matrix4 rot){
	m_rotParent = rot;
	m_update = true;
}
Matrix4 XNode::GetRotationToParent(){
	return m_rotParent;
}

void XNode::UpdateSceneGraph(bool compulsive){
	bool dirty = m_update || compulsive;
	
	if (dirty){
		m_finalMatrix.SetOffset(m_posParent);
		m_finalMatrix *= m_rotParent*m_scale;
		m_update = false;
	}

	Update();
	for each (XNode* child in m_children)
	{
		child->UpdateSceneGraph(dirty);
	}
}